package com.dmbjz.diners.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.dmbjz.common.constant.ApiConstant;
import com.dmbjz.common.constant.RedisKeyConstant;
import com.dmbjz.common.exception.ParameterException;
import com.dmbjz.common.model.domain.ResultInfo;
import com.dmbjz.common.model.vo.NearMeDinerVO;
import com.dmbjz.common.model.vo.ShortDinerInfo;
import com.dmbjz.common.model.vo.SingInDinerInfo;
import com.dmbjz.common.utils.AssertUtil;
import com.google.common.collect.Lists;
import io.swagger.models.auth.In;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/*附近的人服务*/
@Service
@Transactional(rollbackFor = Exception.class)
public class NearMeService {


    @Value("${service.name.ms-oauth-service}")
    private String oauthServiceName;
    @Autowired
    private DinersService dinersService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    /*更新用户坐标*/
    public void updateDinerLocation(String accessToken,Float lon,Float lat){

        /*参数校验*/
        AssertUtil.isTrue(lon==null,"获取经度失败!");
        AssertUtil.isTrue(lat==null,"获取维度失败!");
        /*获取登录用户信息*/
        SingInDinerInfo dinerInfo = loadSignInDinerInfo(accessToken);
        if(dinerInfo==null){
            throw new ParameterException(ApiConstant.NO_LOGIN_CODE,ApiConstant.NO_LOGIN_MESSAGE);
        }
        /*封装Key存入Redis*/
        Point point = new Point(lon.doubleValue(),lat.doubleValue());
        redisTemplate.opsForGeo().add(RedisKeyConstant.diner_location.getKey(),point,dinerInfo.getId());

    }
    /*获取登录用户的信息*/
    public SingInDinerInfo loadSignInDinerInfo(String accessToken){

        AssertUtil.mustLogin(accessToken);
        String url = oauthServiceName+"user/me?access_token={accessToken}";
        ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
        if(resultInfo.getCode()!= ApiConstant.SUCCESS_CODE){
            throw new ParameterException(resultInfo.getMessage());
        }
        SingInDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap)resultInfo.getData(),new SingInDinerInfo(),false);
        if(dinerInfo==null){
            throw new ParameterException(ApiConstant.NO_LOGIN_CODE,ApiConstant.NO_LOGIN_MESSAGE);
        }
        return dinerInfo;

    }



    /*获取附近的人*/
    public List<NearMeDinerVO> findNearMe(String accessToken,Integer radius,Float lon,Float lat){

        /*获取登录用户信息*/
        SingInDinerInfo dinerInfo = loadSignInDinerInfo(accessToken);
        if(dinerInfo==null){
            throw new ParameterException(ApiConstant.NO_LOGIN_CODE,ApiConstant.NO_LOGIN_MESSAGE);
        }
        Integer loginId = dinerInfo.getId();
        String key = RedisKeyConstant.diner_location.getKey();

        /*判断用户是否有上传经纬度，没有到Redis中查询*/
        if(radius==null){
            radius=1000;
        }
        Point point = null;
        if(lon==null || lat==null){
            List<Point> position = redisTemplate.opsForGeo().position(key, loginId);
            AssertUtil.isTrue(CollectionUtil.isEmpty(position),"暂无经纬度");
            point = position.get(0);
        }else{
            point = new Point(lon,lat);
        }

        Distance distance = new Distance(radius,RedisGeoCommands.DistanceUnit.METERS);                                   //初始化距离对象，单位M
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();           //初始化Geo命令对象
        args.limit(20).includeDistance().sortAscending();                                                               //限制返回20个人,包含距离，由远到进进行排序
        Circle circle = new Circle(point,distance);                                                                     //以用户为圆心，创建范围
        GeoResults<RedisGeoCommands.GeoLocation> geoLocation = redisTemplate.opsForGeo().radius(key, circle, args);

        /*创建有序Map*/
        Map<Integer,NearMeDinerVO> nearMap = new LinkedHashMap<>();
        geoLocation.forEach(a->{
            RedisGeoCommands.GeoLocation<Integer> content = a.getContent();
            /*初始化Vo对象*/
            NearMeDinerVO vo = new NearMeDinerVO();
            vo.setId(content.getName());
            double value = a.getDistance().getValue();                           //获取经纬度
            String distanceStr = NumberUtil.round(value,1).toString()+"m"; //保留一位小数四舍五入
            vo.setDistance(distanceStr);
            nearMap.put(content.getName(),vo);
        });

        /*获取附近的人的信息*/
        Integer[] dinerIds = nearMap.keySet().toArray(new Integer[]{});
        List<ShortDinerInfo> shortDinerInfos = dinersService.findByIds(StrUtil.join(",", dinerIds));
        // 完善昵称头像信息
        shortDinerInfos.forEach(shortDinerInfo -> {
            NearMeDinerVO nearMeDinerVO = nearMap.get(shortDinerInfo.getId());
            nearMeDinerVO.setNickname(shortDinerInfo.getNickname());
            nearMeDinerVO.setAvatarUrl(shortDinerInfo.getAvatarUrl());
        });
        return Lists.newArrayList(nearMap.values());

    }



}
